package org.dromara.common.wechat.pay.service

import com.wechat.pay.java.core.RSAPublicKeyConfig
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension
import com.wechat.pay.java.service.payments.jsapi.model.Payer
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse
import com.wechat.pay.java.service.payments.nativepay.NativePayService
import com.wechat.pay.java.service.payments.nativepay.model.Amount
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse
import com.wechat.pay.java.service.refund.RefundService
import com.wechat.pay.java.service.refund.model.AmountReq
import com.wechat.pay.java.service.refund.model.CreateRequest
import com.wechat.pay.java.service.refund.model.Refund
import org.dromara.common.wechat.pay.config.properties.WechatPayProperties
import org.dromara.common.wechat.pay.dto.RechargePrePayDTO
import org.dromara.common.wechat.pay.dto.RefundOrderDTO
import org.springframework.beans.factory.annotation.Value
import org.springframework.web.util.UriComponentsBuilder
import java.math.BigDecimal

class WechatPayService(
    private val wechatPayConfig: RSAPublicKeyConfig,
    private val wechatPayProperties: WechatPayProperties
) {

    @Value("\${server.servlet.context-path}")
    lateinit var contextPath: String

    fun wechatPrePay(bo: RechargePrePayDTO): PrepayResponse {
        val payService = NativePayService.Builder().config(wechatPayConfig).build()
        val prePayRequest = PrepayRequest().apply {
            appid = wechatPayProperties.appId
            mchid = wechatPayProperties.merchantId
            description = bo.remark
            outTradeNo = bo.outTradeNo
            amount = Amount().apply { total = bo.packagePrice.times(BigDecimal(100)).toInt() }
            notifyUrl = UriComponentsBuilder.fromUriString(wechatPayProperties.callbackRoot)
                .path("/")
                .path(contextPath)
                .path(bo.callbackPath)
                .build().toString()
        }
        return payService.prepay(prePayRequest)
    }

    fun wechatJsPrePay(bo: RechargePrePayDTO): PrepayWithRequestPaymentResponse {
        val payService = JsapiServiceExtension.Builder().config(wechatPayConfig).build()
        val prePayRequest = com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest().apply {
            appid = wechatPayProperties.appId
            mchid = wechatPayProperties.merchantId
            description = bo.remark
            outTradeNo = bo.outTradeNo
            amount = com.wechat.pay.java.service.payments.jsapi.model.Amount().apply {
                total = bo.packagePrice.times(BigDecimal(100)).toInt()
            }
            payer = Payer().apply {
                openid = bo.openId
            }
            notifyUrl = UriComponentsBuilder.fromUriString(wechatPayProperties.callbackRoot)
                .path("/")
                .path(contextPath)
                .path(bo.callbackPath)
                .build().toString()
        }
        return payService.prepayWithRequestPayment(prePayRequest)
    }

    fun refundOrder(bo: RefundOrderDTO): Refund {
        val refundService = RefundService.Builder().config(wechatPayConfig).build()
        val refundRequest = CreateRequest().apply {
            transactionId = bo.transactionId
            outRefundNo = bo.outRefundNo
            reason = bo.reason
            amount = AmountReq().apply {
                total = bo.total
                refund = bo.refund
            }
            notifyUrl = UriComponentsBuilder.fromUriString(wechatPayProperties.callbackRoot)
                .path("/")
                .path(contextPath)
                .path(bo.callbackPath)
                .build().toString()
        }
        return refundService.create(refundRequest)
    }
}
